﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DomainModel;
using MusicManagerDAO.Interfaces;
using Microsoft.Practices.Unity;

namespace MusicManager.BL
{
    public class MusicManagerBL : IMusicManagerBL
    {
        [Dependency]
        public IUserDao UserDao { get; set; }
        [Dependency]
        public IMusicDao MusicDao { get; set; }

        private List<string> usersLoggedIn = new List<string>(); 

        public bool CreateUser(int id, string user, string password)
        {
            try
            {
                TransUtil.DoInTransaction(s => AddUserInternal(s), new DomainModel.User(id, user, password));
            }
            catch (UserAlreadyExistsException)
            {
                return false;
            }
            return true;
        }

        public IEnumerable<User> GetUserList()
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return null;
            return users;
        }

        public void AddUserInternal(DomainModel.User user)
        {
            if (!UserDao.Insert(user))
                throw new UserAlreadyExistsException();
        }

        public bool Login(string username, string password, out string token)
        {
            User user = TransUtil.DoInTransaction(() => UserFindByNameAndPassword(username, password));
            if( user == null)
            {
                token = null;
                return false;
            }
            else
            {
                token = CreateToken(user.Id, user.Name, user.Password);
                usersLoggedIn.Add(token);
                return true;
            }

        }

        private string CreateToken(User user)
        {
            return CreateToken(user.Id, user.Name, user.Password);
        }

        private string CreateToken(int id, string name, string password)
        {
            return id + "_" + name + "_" + password;
        } 

        private User UserFindByNameAndPassword(string username, string password)
        {
            return UserDao.FindByNameAndPassword(username, password);
        }

        public bool Logout(string user, string token)
        {
            if (usersLoggedIn.Contains(token))
            {
                usersLoggedIn.Remove(token);
                return true;
            }
            return false;
        }

        public bool AddMusic(string name, byte[] data, string token)
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return false;

            return TransUtil.DoInTransaction(() =>
                                                 {
                                                     User user = users.First(user1 => CreateToken(user1) == token);
                                                     if (user == null) return false;

                                                     IEnumerable<Music> music = MusicDao.FindAllForUser(user);
                                                     if (music.Any(music1 => music1.Name == name))
                                                         throw new DuplicateMusicException();
                                                         
                                                     return MusicDao.Insert(new Music(music.Count() + 1, user.Id, name, data));
                                                 });
        }

        public IEnumerable<string> GetPlaylist(string token)
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return new List<string>();
            User u = GetUserForToken(token);
            IEnumerable<Music> playlist = TransUtil.DoInTransaction(() => MusicDao.FindAllForUser(u));
            return playlist.Select(music => music.Name).ToList();
        }

        private User GetUserForToken(string token)
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return null;

            return TransUtil.DoInTransaction(() => users.FirstOrDefault(user1 => CreateToken(user1) == token));
        }

        public Music GetMusic(string name, string token)
        {
            IEnumerable<Music> playlist = GetPlaylistFull(token);
            if (playlist == null || playlist.Count() == 0)
                return null;

            Music m = playlist.FirstOrDefault(music => music.Name == name);
            if (m == null) return null;

            return m;
        }


        public IEnumerable<User> GetUserByNameLike(string namepart)
        {
            return TransUtil.DoInTransaction(() => UserDao.FindByNameLike(namepart));
        }

        public IEnumerable<Music> GetPlaylistFull(string token)
        {
            IEnumerable<User> users = TransUtil.DoInTransaction(() => UserDao.FindAll());
            if (users == null || !users.Any())
                return new List<Music>();
            User u = GetUserForToken(token);
            IEnumerable<Music> playlist = TransUtil.DoInTransaction(() => MusicDao.FindAllForUser(u));
            return playlist;
        }

    }
}

